﻿namespace MS.Internal.Package
{
    using Microsoft.Windows.Design.Interaction;
    using Microsoft.Windows.Design.PropertyEditing;
    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Globalization;
    using System.IO;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;

    internal static class ToolEncoder
    {
        private static readonly int _cfFormat = DataFormats.GetDataFormat("CF_WINFX_TOOL").Id;
        private const string _format = "CF_WINFX_TOOL";
        private const uint _headerVersion = 1;
        internal const string Key_Bitmap = "Bitmap";
        internal const string Key_CreationAssemblyCache = "CreationAssemblyCache";
        internal const string Key_CreationAssemblyName = "CreationAssemblyName";
        internal const string Key_CreationTypeInternal = "CreationTypeInternal";
        internal const string Key_CreationTypeName = "CreationTypeName";
        internal const string Key_ToolTypeName = "ToolTypeName";

        internal static IDictionary Decode(IntPtr toolPtr)
        {
            return UnpackWinfxTool(toolPtr);
        }

        internal static byte[] Encode(IDictionary properties)
        {
            return PackWinfxTool(properties);
        }

        private static TypeConverter GetConverter(Type type)
        {
            if (type == typeof(AssemblyName))
            {
                return new AssemblyNameConverter();
            }
            if (type == typeof(byte[]))
            {
                return new ByteArrayConverter();
            }
            return TypeDescriptor.GetConverter(type);
        }

        internal static IDictionary GetToolProperties(Tool tool)
        {
            if (tool == null)
            {
                throw new ArgumentNullException("tool");
            }
            IDictionary dictionary = new Hashtable();
            dictionary["ToolTypeName"] = tool.GetType().AssemblyQualifiedName;
            CreationTool tool2 = tool as CreationTool;
            if (tool2 != null)
            {
                dictionary["CreationTypeName"] = tool2.CreationType.AssemblyQualifiedName;
                dictionary["CreationTypeInternal"] = !tool2.CreationType.IsPublic;
                dictionary["CreationAssemblyName"] = tool2.CreationType.Assembly.GetName(false);
                dictionary["CreationAssemblyCache"] = tool2.CreationType.Assembly.GlobalAssemblyCache;
                dictionary["Bitmap"] = null;
                using (MemoryStream stream = new MemoryStream())
                {
                    BitmapSource source = null;
                    NewItemFactory factory = new NewItemFactory();
                    string imageName = null;
                    Stream stream2 = factory.GetImageStream(tool2.CreationType, new Size(16.0, 16.0), out imageName);
                    Image image = null;
                    if (stream2 != null)
                    {
                        BitmapImage image2 = new BitmapImage();
                        image2.BeginInit();
                        image2.StreamSource = stream2;
                        image2.EndInit();
                        image = new Image {
                            Source = image2
                        };
                    }
                    if (image != null)
                    {
                        source = image.Source as BitmapSource;
                        if ((source.PixelHeight != 0x10) || (source.PixelWidth != 0x10))
                        {
                            Transform newTransform = new ScaleTransform(16.0 / ((double) source.PixelWidth), 16.0 / ((double) source.PixelHeight));
                            source = new TransformedBitmap(source, newTransform);
                        }
                    }
                    if (source == null)
                    {
                        return dictionary;
                    }
                    if (source.Format != PixelFormats.Rgb24)
                    {
                        source = new FormatConvertedBitmap(source, PixelFormats.Pbgra32, null, 0.0);
                    }
                    BitmapEncoder encoder = new BmpBitmapEncoder();
                    BitmapFrame item = BitmapFrame.Create(source);
                    encoder.Frames.Add(item);
                    encoder.Save(stream);
                    stream.Close();
                    dictionary["Bitmap"] = stream.GetBuffer();
                }
            }
            return dictionary;
        }

        internal static IDictionary GetToolProperties(string typeName, bool isInternal, AssemblyName assemblyName)
        {
            if (typeName == null)
            {
                throw new ArgumentNullException("typeName");
            }
            IDictionary dictionary = new Hashtable();
            dictionary["ToolTypeName"] = string.Format(CultureInfo.InvariantCulture, "MS.Internal.Creation.ControlCreationTool, {0}", new object[] { "Microsoft.Windows.Design.Developer, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" });
            dictionary["CreationTypeName"] = string.Format(CultureInfo.InvariantCulture, "{0}, {1}", new object[] { typeName, assemblyName.FullName });
            dictionary["CreationTypeInternal"] = isInternal;
            dictionary["CreationAssemblyName"] = assemblyName;
            dictionary["CreationAssemblyCache"] = false;
            dictionary["Bitmap"] = null;
            return dictionary;
        }

        private static unsafe byte[] PackWinfxTool(IDictionary values)
        {
            WINFXTOOL structure = new WINFXTOOL();
            int num = Marshal.SizeOf(structure);
            int num2 = num;
            int num3 = 0;
            int num4 = 0;
            int num5 = 0;

            IEnumerator enumerator = values.Values.GetEnumerator();
            while (enumerator.MoveNext())
            {
                if (enumerator.Current != null)
                {
                    num5++;
                }
            }
            byte[] bytes = Encoding.Unicode.GetBytes(new char[1]);
            byte[][] bufferArray = new byte[num5][];
            byte[][] bufferArray2 = new byte[num5][];
            byte[][] bufferArray3 = new byte[num5][];
            int index = 0;
            foreach (DictionaryEntry entry in values)
            {
                if (entry.Value != null)
                {
                    Type type = entry.Value.GetType();
                    string s = GetConverter(type).ConvertToInvariantString(entry.Value);
                    bufferArray[index] = Encoding.Unicode.GetBytes((string) entry.Key);
                    bufferArray2[index] = Encoding.Unicode.GetBytes(type.AssemblyQualifiedName);
                    bufferArray3[index] = Encoding.Unicode.GetBytes(s);
                    int num7 = bufferArray[index].Length + bytes.Length;
                    int num8 = bufferArray2[index].Length + bytes.Length;
                    num3 += num7;
                    num4 += num8;
                    num2 += ((num7 + num8) + bufferArray3[index].Length) + bytes.Length;
                    index++;
                }
            }
            structure.dwVersion = 1;
            structure.dwItemCount = (uint) num5;
            structure.dwKeys = (uint) num;
            structure.dwValueTypes = structure.dwKeys + ((uint) num3);
            structure.dwValues = structure.dwValueTypes + ((uint) num4);
            byte[] array = new byte[num2];
            byte* numPtr = (byte*) &structure;
            for (int i = 0; i < num; i++)
            {
                array[i] = numPtr[i];
            }
            int num10 = num;
            for (index = 0; index < bufferArray.Length; index++)
            {
                bufferArray[index].CopyTo(array, num10);
                num10 += bufferArray[index].Length;
                bytes.CopyTo(array, num10);
                num10 += bytes.Length;
            }
            for (index = 0; index < bufferArray2.Length; index++)
            {
                bufferArray2[index].CopyTo(array, num10);
                num10 += bufferArray2[index].Length;
                bytes.CopyTo(array, num10);
                num10 += bytes.Length;
            }
            for (index = 0; index < bufferArray3.Length; index++)
            {
                bufferArray3[index].CopyTo(array, num10);
                num10 += bufferArray3[index].Length;
                bytes.CopyTo(array, num10);
                num10 += bytes.Length;
            }
            return array;
        }

        private static unsafe string UnpackString(IntPtr ptr, ref int offset)
        {
            byte* numPtr = (byte*) ptr;
            numPtr += offset;
            string str = Marshal.PtrToStringUni((IntPtr) numPtr);
            offset += (str.Length + 1) * 2;
            return str;
        }

        private static IDictionary UnpackWinfxTool(IntPtr toolPtr)
        {
            WINFXTOOL winfxtool = (WINFXTOOL) Marshal.PtrToStructure(toolPtr, typeof(WINFXTOOL));
            if (winfxtool.dwVersion > 1)
            {
                return null;
            }
            string[] strArray = new string[winfxtool.dwItemCount];
            int dwKeys = (int) winfxtool.dwKeys;
            for (int i = 0; i < strArray.Length; i++)
            {
                strArray[i] = UnpackString(toolPtr, ref dwKeys);
            }
            TypeConverter[] converterArray = new TypeConverter[winfxtool.dwItemCount];
            dwKeys = (int) winfxtool.dwValueTypes;
            for (int j = 0; j < strArray.Length; j++)
            {
                Type type = Type.GetType(UnpackString(toolPtr, ref dwKeys), true);
                converterArray[j] = GetConverter(type);
            }
            IDictionary dictionary = new Hashtable(strArray.Length);
            dwKeys = (int) winfxtool.dwValues;
            for (int k = 0; k < strArray.Length; k++)
            {
                string text = UnpackString(toolPtr, ref dwKeys);
                object obj2 = converterArray[k].ConvertFromInvariantString(text);
                dictionary.Add(strArray[k], obj2);
            }
            return dictionary;
        }

        internal static int ClipboardFormat
        {
            get
            {
                return _cfFormat;
            }
        }

        private class AssemblyNameConverter : TypeConverter
        {
            public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
            {
                return (typeof(string) == sourceType);
            }

            public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
            {
                return (typeof(string) == destinationType);
            }

            public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
            {
                string str = value as string;
                if (str == null)
                {
                    return base.ConvertFrom(context, culture, value);
                }
                string[] strArray = str.Split(new char[] { ',', ' ' });
                string str2 = null;
                StringBuilder builder = new StringBuilder();
                foreach (string str3 in strArray)
                {
                    if (str3.Length > 0)
                    {
                        if (str3.ToUpperInvariant().Contains("CODEBASE"))
                        {
                            string[] strArray2 = str3.Split(new char[] { '=' });
                            if (strArray2.Length > 1)
                            {
                                str2 = strArray2[1];
                            }
                        }
                        else
                        {
                            if (builder.Length > 0)
                            {
                                builder.Append(", ");
                            }
                            builder.Append(str3);
                        }
                    }
                }
                AssemblyName name = new AssemblyName(builder.ToString());
                if (str2 != null)
                {
                    name.CodeBase = str2;
                }
                return name;
            }

            public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
            {
                if (!(typeof(string) == destinationType))
                {
                    return base.ConvertTo(context, culture, value, destinationType);
                }
                AssemblyName name = (AssemblyName) value;
                string str = name.ToString();
                if (!string.IsNullOrEmpty(name.CodeBase))
                {
                    str = string.Format(CultureInfo.InvariantCulture, "{0}, CodeBase={1}", new object[] { str, name.EscapedCodeBase });
                }
                return str;
            }
        }

        private class ByteArrayConverter : TypeConverter
        {
            public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
            {
                return (typeof(string) == sourceType);
            }

            public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
            {
                return (typeof(string) == destinationType);
            }

            public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
            {
                string s = value as string;
                if (s != null)
                {
                    return Convert.FromBase64String(s);
                }
                return base.ConvertFrom(context, culture, value);
            }

            public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
            {
                if (typeof(string) == destinationType)
                {
                    byte[] inArray = (byte[]) value;
                    return Convert.ToBase64String(inArray);
                }
                return base.ConvertTo(context, culture, value, destinationType);
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct WINFXTOOL
        {
            public uint dwVersion;
            public uint dwItemCount;
            public uint dwKeys;
            public uint dwValueTypes;
            public uint dwValues;
        }
    }
}

